package main

import (
	"bytes"
	"encoding/binary"
	"encoding/json"
	"errors"
	"fmt"

	log "github.com/sirupsen/logrus"
)

// BytesParser parse analog data
type BytesParser struct {
	Type  string
	head  string
	items []ParserItem
}

// NewBytesParser create new analog parser
func NewBytesParser(config ParserConfig) (BytesParser, error) {
	a := BytesParser{
		Type:  config.Type,
		head:  string(config.Head.Data),
		items: config.Items,
	}
	return a, nil
}

func (ap BytesParser) parse(rdata rdata) (string, error) {
	prop, ok := rdata.GetProperty("sourceName")
	if !ok {
		return "", errors.New("unmatch data, no data byte")
	}
	switch prop := prop.(type) {
	case string:
		{
			if prop != "BYTES" { // nolint
				return "", errors.New("unmatch data, not bytes")
			}
		}
	}
	data := rdata.Data()
	if len(data) <= 4 {
		return "", errors.New("parser: unmatch data, too short data")
	}
	head := string(data[:4])
	if head != ap.head {
		return "", errors.New("parser: unmatch data, head not match")
	}
	log.WithFields(log.Fields{"type": ap.Type, "head": head}).Info("got data")
	mapping := map[string]interface{}{}
	for _, item := range ap.items {
		bs := data[item.Offset : item.Offset+item.Len]
		buf := bytes.NewReader(bs)
		v, err := decodeBytes(buf, item)
		if err != nil {
			log.WithFields(log.Fields{"err": err, "type": ap.Type, "head": ap.head}).Info("error parse data")
			return "", err
		}
		mapping[item.Path] = v
	}
	s, err := json.Marshal(mapping)
	// log.WithFields(log.Fields{
	// 	"type": ap.Type,
	// 	"head": ap.head,
	// 	"data": fmt.Sprintf("%+v", mapping),
	// }).Info("parsed data")
	return string(s), err
}

func decodeBytes(buf *bytes.Reader, item ParserItem) (interface{}, error) {
	switch item.Type {
	case "FLOAT":
		{
			var f float32
			err := binary.Read(buf, binary.LittleEndian, &f)
			if err != nil {
				return 0.0, err
			}
			return f, nil
		}
	default:
		{
			return 0, fmt.Errorf("unknonw ParserItem type: %s", item.Type)
		}
	}
}
